package com.lx.cp.netty.server;

import com.lx.cp.netty.handler.TcpServerHandler;
import com.lx.cp.utils.MsgUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.EventExecutorGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

/**
 * netty服务（TCP）
 */
@Slf4j
@Component
public class NettyTcpServer implements ApplicationListener<ApplicationStartedEvent> {

    @Value("${gps.netty.tcp.port}")
    private int port;
    
    @Value("${gps.netty.tcp.read-timeout}")
    private int readTimeOut;

    @Autowired
    @Qualifier("bossGroup")
    private NioEventLoopGroup bossGroup;

    @Autowired
    @Qualifier("workerGroup")
    private NioEventLoopGroup workerGroup;
    
    @Autowired
    @Qualifier("businessGroup")
    private EventExecutorGroup businessGroup;

    @Autowired
    private TcpServerHandler tcpServerHandler;

    /**
     * 启动Server
     *
     */
    @Override
	public void onApplicationEvent(ApplicationStartedEvent event) {
    	try {
	        ServerBootstrap serverBootstrap = new ServerBootstrap();
	        serverBootstrap.group(bossGroup, workerGroup)
	                .channel(NioServerSocketChannel.class)
	                .childHandler(new ChannelInitializer<SocketChannel>() { //
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ch.pipeline().addLast(new IdleStateHandler(readTimeOut, 0, 0, TimeUnit.MINUTES));
							// 1024表示单条消息的最大长度，解码器在查找分隔符的时候，达到该长度还没找到的话会抛异常
							ch.pipeline().addLast(
									new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer(new byte[] { MsgUtil.DELIMITER }),
											Unpooled.copiedBuffer(new byte[] { MsgUtil.DELIMITER, MsgUtil.DELIMITER })));
							ch.pipeline().addLast(businessGroup,tcpServerHandler);
						}
					})
	                .option(ChannelOption.SO_BACKLOG, 1024) //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
	                .childOption(ChannelOption.TCP_NODELAY, true)//立即写出
	                .childOption(ChannelOption.SO_KEEPALIVE, true);//长连接
	        ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
	        if (channelFuture.isSuccess()) {
				log.info("TCP服务启动完毕,port={}", port);
	        }
    	}catch(Exception e) {
			log.info("TCP服务启动失败", e);
    	}
    }

    /**
     * 销毁资源
     */
    @PreDestroy
    public void destroy() {
        bossGroup.shutdownGracefully().syncUninterruptibly();
        workerGroup.shutdownGracefully().syncUninterruptibly();
        log.info("TCP服务关闭成功");
    }
}
